﻿using Batman.DLL.UserModule.Models;
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Mappers;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;
using System.Reflection;

namespace Batman.DLL.UserModule
{
    public static class Startup
    {
        /// <summary>
        /// 要在.addMvc之后添加
        /// </summary>
        /// <param name="services"></param>
        public static IIdentityServerBuilder AddId4(this IServiceCollection services, string connStr)
        {
            // 配合AspNet.Identity
            services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(connStr));
            services.AddIdentity<User, Role>()
                .AddEntityFrameworkStores<ApplicationDbContext>()
                .AddDefaultTokenProviders()
                ;
            var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

            return services.AddIdentityServer(options =>
                {
                    options.Events.RaiseErrorEvents = true;
                    options.Events.RaiseInformationEvents = true;
                    options.Events.RaiseFailureEvents = true;
                    options.Events.RaiseSuccessEvents = true;

                   // see https://identityserver4.readthedocs.io/en/latest/topics/resources.html
                   options.EmitStaticAudienceClaim = true;
                }).AddDeveloperSigningCredential().AddConfigurationStore(opt =>
                   {
                       opt.ConfigureDbContext = context =>
                       {
                           context.UseMySql(connStr, sql =>
                           {
                               sql.MigrationsAssembly(migrationsAssembly);
                           });
                       };
                   })
                  .AddOperationalStore(opt =>
                  {
                      opt.ConfigureDbContext = context =>
                      {
                          context.UseMySql(connStr, sql =>
                          {
                              sql.MigrationsAssembly(migrationsAssembly);
                          });
                      };
                  })
                  .AddAspNetIdentity<User>();
        }

        public static async void InitializeDatabase(this IApplicationBuilder app)
        {
            using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
            {
                var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
                context.Database.Migrate();
                var userManager = serviceScope.ServiceProvider.GetRequiredService<UserManager<User>>();
                var roleManager = serviceScope.ServiceProvider.GetRequiredService<RoleManager<Role>>();

                if (!context.ApiScopes.Any())
                {
                    foreach (var apiScope in Default.GetApiScopes())
                    {
                        context.ApiScopes.Add(apiScope.ToEntity());
                    }
                    context.SaveChanges();
                }

                if (!context.Clients.Any())
                {
                    foreach (var client in Default.GetClients())
                    {
                        context.Clients.Add(client.ToEntity());
                    }
                    context.SaveChanges();
                }

                if (!context.IdentityResources.Any())
                {
                    foreach (var resource in Default.GetIdentityResources())
                    {
                        context.IdentityResources.Add(resource.ToEntity());
                    }
                    context.SaveChanges();
                }

                if (!context.ApiResources.Any())
                {
                    foreach (var resource in Default.GetApiResources())
                    {
                        var apiResource = resource.ToEntity();
                        //var scopes = context.ApiScopes.Where(t => apiResource.Scopes.Any(s => s.Scope == resource.Name)).ToList();
                        //apiResource.Scopes = scopes;

                        context.ApiResources.Add(apiResource);
                    }
                    context.SaveChanges();
                }

                //添加config中的Users数据到数据库
                if (!userManager.Users.Any())
                {
                    foreach (var user in Default.GetUsers())
                    {
                        User iuser = new User()
                        {
                            UserName = user.Username
                        };
                        iuser.PasswordHash = userManager.PasswordHasher.HashPassword(iuser, user.Password);
                        var createResult = await userManager.CreateAsync(iuser);
                    }
                }

                //添加config中的Users数据到数据库
                if (!roleManager.Roles.Any())
                {
                    foreach (var role in Default.GetRoles())
                    {
                        var createResult = await roleManager.CreateAsync(role);
                    }
                }
            }
        }
    }
}
